package com.lyf.scm.admin.domain.util;


import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.lyf.scm.admin.api.dto.*;
import com.lyf.scm.admin.domain.remote.allocationservice.dto.OtherTargetEchartResultDTO;
import com.lyf.scm.admin.domain.remote.allocationservice.dto.OtherTargetResultDTO;
import com.lyf.scm.common.constants.CommonConstants;
import com.lyf.scm.common.enums.*;
import com.lyf.scm.common.util.ChannelUtil;
import com.lyf.scm.common.model.SalesPlanSelectDTO;
import org.apache.commons.collections4.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import static com.lyf.scm.common.enums.OtherTargetsEnum.*;
import static java.util.stream.Collectors.groupingBy;

/**
 * 其它指标处理工具类
 *
 * @author wangchlei
 * @date 2020/11/12
 */
public class OtherTargetHandleUtil {
    /**
     * 初始化集合 size = 14，每个元素值为0
     */
    public static final List<BigDecimal> ZERO_BIGDECIMAL = new ArrayList<>();

    static {
        for (int i = 0; i < 14; i++) {
            ZERO_BIGDECIMAL.add(BigDecimal.ZERO);
        }
    }

    /**
     * 获取通用查询DTO(列表)
     *
     * @param esAggregationDTO
     * @param esReturnDTOS
     * @param otherTargetsEnums
     * @return {@link OtherTargetGeneralQueryDTO}
     **/
    public static OtherTargetGeneralQueryDTO getGeneralQueryDTO(EsAggregationDTO esAggregationDTO, List<EsReturnDTO> esReturnDTOS, List<OtherTargetsEnum> otherTargetsEnums) {
        OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO = new OtherTargetGeneralQueryDTO();
        if (CollectionUtils.isEmpty(esReturnDTOS)) {
            return otherTargetGeneralQueryDTO;
        }
        if (esAggregationDTO.getGroupColumns() != null) {
            //聚合区域等级
            otherTargetGeneralQueryDTO.setAreaLevel(getAreaLevel(esAggregationDTO.getGroupColumns()));
        }
        otherTargetGeneralQueryDTO.setUnitType(esAggregationDTO.getUnitType());
        //其他渠道计划没有根据区域分组
        if (null == otherTargetGeneralQueryDTO.getAreaLevel()) {
            //获取不同的区域名称
            List<String> areaList = esReturnDTOS.stream().filter(item -> ObjectUtil.isNotNull(item.getArea())).map(EsReturnDTO::getArea).distinct().collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(areaList)) {
                Integer areaLevel = areaList.stream().map(area -> {
                    Integer level = null;
                    String[] areaArr = area.split("/");
                    switch (areaArr.length) {
                        case 1:
                            level = CommonConstants.AREA_LEVEL_ONE;
                            break;
                        case 2:
                            level = CommonConstants.AREA_LEVEL_TWO;
                            break;
                        case 3:
                            level = CommonConstants.AREA_LEVEL_THREE;
                            break;
                        case 4:
                            level = CommonConstants.AREA_LEVEL_FOUR;
                            break;
                        default:
                            break;
                    }
                    return level;
                }).max(Integer::compareTo).get();
                otherTargetGeneralQueryDTO.setAreaLevel(areaLevel);
            }
        }
        //渠道集合
        List<String> channelList = new ArrayList<>();
        //区域编码集合
        List<String> areaCodes = new ArrayList<>();
        //sku集合
        List<String> skuCodes = new ArrayList<>();
        //仓库集合
        List<String> warehouseCodes = new ArrayList<>();
        for (EsReturnDTO esReturnDTO : esReturnDTOS) {
            channelList.add(esReturnDTO.getChannel());
            areaCodes.add(esReturnDTO.getAreaCode());
            skuCodes.add(esReturnDTO.getSkuCode());
            warehouseCodes.add(esReturnDTO.getDeliverId());
        }
        otherTargetGeneralQueryDTO.setChannelList(channelList.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()));
        otherTargetGeneralQueryDTO.setAreaCodes(areaCodes.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()));
        otherTargetGeneralQueryDTO.setSkuList(skuCodes.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()));
        otherTargetGeneralQueryDTO.setDeliverIds(warehouseCodes.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()));
        List<String> dateList = esAggregationDTO.getDateList();
        otherTargetGeneralQueryDTO.setDateList(dateList);
        otherTargetGeneralQueryDTO.setStartDate(dateList.get(0));
        String endDate = DateUtil.format(DateUtil.offset(DateUtil.parse(dateList.get(dateList.size() - 1), DatePattern.NORM_DATE_PATTERN), DateField.DAY_OF_MONTH, 6), DatePattern.NORM_DATE_PATTERN);
        otherTargetGeneralQueryDTO.setEngDate(endDate);
        //采购中心DTO
        setPurchaseDTO(otherTargetsEnums, otherTargetGeneralQueryDTO, esReturnDTOS, otherTargetGeneralQueryDTO.getStartDate(), endDate);
        //实时库存参数
        otherTargetGeneralQueryDTO.setBusinessType(5);
        otherTargetGeneralQueryDTO.setType(0);
        //设置所有其它指标
        otherTargetGeneralQueryDTO.setOtherTargetsEnum(otherTargetsEnums);
        return otherTargetGeneralQueryDTO;
    }

    /**
     * 采购中心DTO
     *
     * @param otherTargetsEnums
     * @param otherTargetGeneralQueryDTO
     * @param esReturnDTOS
     * @param startDate
     * @param endDate
     * @return void
     **/
    private static void setPurchaseDTO(List<OtherTargetsEnum> otherTargetsEnums, OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO, List<EsReturnDTO> esReturnDTOS, String startDate, String endDate) {
        if (otherTargetsEnums.contains(BATCH_PURCHASE_ORDER_TARGET) || otherTargetsEnums.contains(ACTUAL_QTY) || otherTargetsEnums.contains(ACTUAL_STORAGE_QTY)) {
            if (CollectionUtils.isNotEmpty(esReturnDTOS)) {
                List<PoQtyQueryDTO> poQtyQueryDTOS = new ArrayList<>(esReturnDTOS.stream().collect(groupingBy(EsReturnDTO::getDeliverId, Collectors.collectingAndThen(Collectors.toList(), values -> {
                    PoQtyQueryDTO poQtyQueryDTO = new PoQtyQueryDTO();
                    poQtyQueryDTO.setArrivalStartDate(startDate);
                    poQtyQueryDTO.setArrivalEndDate(endDate);
                    poQtyQueryDTO.setSkuCodeList(values.stream().map(EsReturnDTO::getSkuCode).distinct().collect(Collectors.toList()));
                    poQtyQueryDTO.setWarehouseCode(values.get(0).getDeliverId());
                    return poQtyQueryDTO;
                }))).values());
                otherTargetGeneralQueryDTO.setPoQtyQueryDTOS(poQtyQueryDTOS);
            }
        }
    }

    /**
     * 获取通用查询DTO(图表)
     *
     * @param esAggregationDTO
     * @param otherTargetsEnums
     * @return {@link OtherTargetGeneralQueryDTO}
     **/
    public static OtherTargetGeneralQueryDTO getGeneralEchartQueryDTO(EsAggregationDTO esAggregationDTO, List<OtherTargetsEnum> otherTargetsEnums, List<String> skuCodes) {
        OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO = new OtherTargetGeneralQueryDTO();
        //渠道集合
        List<String> channelList = esAggregationDTO.getEsQuery().getChannelCodeList();
        //仓库集合
        List<String> warehouseCodes = esAggregationDTO.getEsQuery().getWarehouseCodeList();
        otherTargetGeneralQueryDTO.setUnitType(esAggregationDTO.getUnitType());
        if (!CollectionUtils.isEmpty(channelList)) {
            otherTargetGeneralQueryDTO.setChannelList(channelList.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()));
        }
        if (!CollectionUtils.isEmpty(esAggregationDTO.getEsQuery().getQueryAreaCodeList())) {
            //区域编码集合
            otherTargetGeneralQueryDTO.setAreaCodes(esAggregationDTO.getEsQuery().getQueryAreaCodeList().stream().map(SalesPlanSelectDTO::getCode).distinct().filter(Objects::nonNull).collect(Collectors.toList()));
        }
        if (!CollectionUtils.isEmpty(skuCodes)) {
            otherTargetGeneralQueryDTO.setSkuList(skuCodes.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()));
        }
        if (!CollectionUtils.isEmpty(warehouseCodes)) {
            otherTargetGeneralQueryDTO.setDeliverIds(warehouseCodes.stream().filter(Objects::nonNull).distinct().collect(Collectors.toList()));
        }
        List<String> dateList = esAggregationDTO.getDateList();
        otherTargetGeneralQueryDTO.setDateList(dateList);
        otherTargetGeneralQueryDTO.setStartDate(dateList.get(0));
        String endDate = DateUtil.format(DateUtil.offset(DateUtil.parse(dateList.get(dateList.size() - 1), DatePattern.NORM_DATE_PATTERN), DateField.DAY_OF_MONTH, 6), DatePattern.NORM_DATE_PATTERN);
        otherTargetGeneralQueryDTO.setEngDate(endDate);
        //采购中心DTO
        setEchartPurchaseDTO(otherTargetsEnums, otherTargetGeneralQueryDTO, otherTargetGeneralQueryDTO.getStartDate(), endDate);
        //实时库存参数
        otherTargetGeneralQueryDTO.setBusinessType(5);
        otherTargetGeneralQueryDTO.setType(0);
        //设置所有其它指标
        otherTargetGeneralQueryDTO.setOtherTargetsEnum(otherTargetsEnums);
        return otherTargetGeneralQueryDTO;
    }

    /**
     * 采购中心DTO
     *
     * @param otherTargetsEnums
     * @param otherTargetGeneralQueryDTO
     * @param startDate
     * @param endDate
     * @return void
     **/
    private static void setEchartPurchaseDTO(List<OtherTargetsEnum> otherTargetsEnums, OtherTargetGeneralQueryDTO otherTargetGeneralQueryDTO, String startDate, String endDate) {
        if (otherTargetsEnums.contains(BATCH_PURCHASE_ORDER_TARGET) || otherTargetsEnums.contains(ACTUAL_QTY) || otherTargetsEnums.contains(ACTUAL_STORAGE_QTY)) {
            PoQtyAggregationQueryDTO poQtyAggregationQueryDTO = new PoQtyAggregationQueryDTO();
            poQtyAggregationQueryDTO.setSkuCodeList(otherTargetGeneralQueryDTO.getSkuList());
            poQtyAggregationQueryDTO.setWarehouseCodeList(otherTargetGeneralQueryDTO.getDeliverIds());
            poQtyAggregationQueryDTO.setArrivalStartDate(startDate);
            poQtyAggregationQueryDTO.setArrivalEndDate(endDate);
            otherTargetGeneralQueryDTO.setPoQtyAggregationQueryDTOs(poQtyAggregationQueryDTO);
        }
    }

    /**
     * 获取聚合区域层级
     *
     * @param groupColumns
     * @return {@link Integer}
     **/
    private static Integer getAreaLevel(List<String> groupColumns) {
        if (groupColumns.contains(EsConmulEnum.PROVINCE_CODE_KEYWORD.getFName())) {
            return CommonConstants.AREA_LEVEL_ONE;
        }
        if (groupColumns.contains(EsConmulEnum.CITY_CODE_KEYWORD.getFName())) {
            return CommonConstants.AREA_LEVEL_TWO;
        }
        if (groupColumns.contains(EsConmulEnum.COUNTY_CODE_KEYWORD.getFName())) {
            return CommonConstants.AREA_LEVEL_THREE;
        }
        if (groupColumns.contains(EsConmulEnum.STORE_KEYWORD.getFName())) {
            return CommonConstants.AREA_LEVEL_FOUR;
        }
        return null;
    }

    /**
     * 处理列表结果集
     *
     * @param otherTargetResultDTOs
     * @param result
     * @return void
     **/
    public static void handleResult(List<OtherTargetResultDTO> otherTargetResultDTOs, List<EsReturnDTO> result) {
        BaseOtherTargetEnum baseOtherTargetEnum;
        for (OtherTargetResultDTO item : otherTargetResultDTOs) {
            baseOtherTargetEnum = item.getOtherTargetsEnum();
            //实际销量
            if (OtherTargetsEnum.ACTUAL_SALES == baseOtherTargetEnum) {
                handleActualSales(item.getResult(), result, item.getType());
                continue;
            }
            //实时库存
            if (OtherTargetsEnum.REAL_TIME_STOCK == baseOtherTargetEnum) {
                handleRealTimeStock(item.getResult(), result, OtherTargetsEnum.REAL_TIME_STOCK.getName());
                continue;
            }
            //已确认的采购订单数量
            if (PurchaseOrderTargetEnum.CONFIRMED_PURCHASE_ORDERS == baseOtherTargetEnum) {
                handlePurchaseTarget(item.getResult(), result, PurchaseOrderTargetEnum.CONFIRMED_PURCHASE_ORDERS.getName());
                continue;
            }
            //预约在途采购数量
            if (PurchaseOrderTargetEnum.APPOINTMENT_PURCHASE_QUANTITY == baseOtherTargetEnum) {
                handlePurchaseTarget(item.getResult(), result, PurchaseOrderTargetEnum.APPOINTMENT_PURCHASE_QUANTITY.getName());
                continue;
            }
            //采购订单数量
            if (PurchaseOrderTargetEnum.PURCHASE_ORDER_QUANTITY == baseOtherTargetEnum) {
                handlePurchaseTarget(item.getResult(), result, PurchaseOrderTargetEnum.PURCHASE_ORDER_QUANTITY.getName());
                continue;
            }
            //采购计划数量
            if (PurchaseOrderTargetEnum.PURCHASE_PLAN_QUANTITY == baseOtherTargetEnum) {
                handlePurchaseTarget(item.getResult(), result, PurchaseOrderTargetEnum.PURCHASE_PLAN_QUANTITY.getName());
                continue;
            }
            //未履约采购数量
            if (PurchaseOrderTargetEnum.UNFULFILLED_PURCHASE_QUANTITY == baseOtherTargetEnum) {
                handlePurchaseTarget(item.getResult(), result, PurchaseOrderTargetEnum.UNFULFILLED_PURCHASE_QUANTITY.getName());
                continue;
            }
            //安全库存量
            if (TiSsEnum.STOCK_SAFETY == baseOtherTargetEnum) {
                handleRealTimeStock(item.getResult(), result, TiSsEnum.STOCK_SAFETY.getName());
                continue;
            }
            //目标库存数量
            if (TiSsEnum.TARGET_INVENTORY == baseOtherTargetEnum) {
                handleRealTimeStock(item.getResult(), result, TiSsEnum.TARGET_INVENTORY.getName());
                continue;
            }
            //覆盖天数
            if (TiSsEnum.COVERED_DAYS == baseOtherTargetEnum) {
                handleRealTimeStock(item.getResult(), result, TiSsEnum.COVERED_DAYS.getName());
                continue;
            }
            //实际到仓数量
            if (OtherTargetsEnum.ACTUAL_QTY == baseOtherTargetEnum) {
                handlePurchaseTarget(item.getResult(), result, OtherTargetsEnum.ACTUAL_QTY.getName());
                continue;
            }
            //实际入库数量
            if (OtherTargetsEnum.ACTUAL_STORAGE_QTY == baseOtherTargetEnum) {
                handlePurchaseTarget(item.getResult(), result, OtherTargetsEnum.ACTUAL_STORAGE_QTY.getName());
            }
        }
    }

    /**
     * 处理图表结果集
     *
     * @param echartNecessaryOtherTargets
     * @param value
     * @return void
     **/
    public static void handleEchartResult(List<OtherTargetEchartResultDTO> echartNecessaryOtherTargets, Map<String, List<BigDecimal>> value) {
        BaseOtherTargetEnum baseOtherTargetEnum;
        for (OtherTargetEchartResultDTO item : echartNecessaryOtherTargets) {
            baseOtherTargetEnum = item.getOtherTargetsEnum();
            //实际销量
            if (OtherTargetsEnum.ACTUAL_SALES == baseOtherTargetEnum) {
                value.put(OtherTargetsEnum.ACTUAL_SALES.getName(), item.getResult());
                continue;
            }
            //实时库存
            if (OtherTargetsEnum.REAL_TIME_STOCK == baseOtherTargetEnum) {
                value.put(OtherTargetsEnum.REAL_TIME_STOCK.getName(), item.getResult());
                continue;
            }
            //已确认的采购订单数量
            if (PurchaseOrderTargetEnum.CONFIRMED_PURCHASE_ORDERS == baseOtherTargetEnum) {
                value.put(PurchaseOrderTargetEnum.CONFIRMED_PURCHASE_ORDERS.getName(), item.getResult());
                continue;
            }
            //预约在途采购数量
            if (PurchaseOrderTargetEnum.APPOINTMENT_PURCHASE_QUANTITY == baseOtherTargetEnum) {
                value.put(PurchaseOrderTargetEnum.APPOINTMENT_PURCHASE_QUANTITY.getName(), item.getResult());
                continue;
            }
            //采购订单数量
            if (PurchaseOrderTargetEnum.PURCHASE_ORDER_QUANTITY == baseOtherTargetEnum) {
                value.put(PurchaseOrderTargetEnum.PURCHASE_ORDER_QUANTITY.getName(), item.getResult());
                continue;
            }
            //采购计划数量
            if (PurchaseOrderTargetEnum.PURCHASE_PLAN_QUANTITY == baseOtherTargetEnum) {
                value.put(PurchaseOrderTargetEnum.PURCHASE_PLAN_QUANTITY.getName(), item.getResult());
                continue;
            }
            //未履约采购数量
            if (PurchaseOrderTargetEnum.UNFULFILLED_PURCHASE_QUANTITY == baseOtherTargetEnum) {
                value.put(PurchaseOrderTargetEnum.UNFULFILLED_PURCHASE_QUANTITY.getName(), item.getResult());
                continue;
            }
            //安全库存量
            if (TiSsEnum.STOCK_SAFETY == baseOtherTargetEnum) {
                value.put(TiSsEnum.STOCK_SAFETY.getName(), item.getResult());
                continue;
            }
            //目标库存数量
            if (TiSsEnum.TARGET_INVENTORY == baseOtherTargetEnum) {
                value.put(TiSsEnum.TARGET_INVENTORY.getName(), item.getResult());
                continue;
            }
            //覆盖天数
            if (TiSsEnum.COVERED_DAYS == baseOtherTargetEnum) {
                value.put(TiSsEnum.COVERED_DAYS.getName(), item.getResult());
                continue;
            }
            //实际到仓数量
            if (OtherTargetsEnum.ACTUAL_QTY == baseOtherTargetEnum) {
                value.put(OtherTargetsEnum.ACTUAL_QTY.getName(), item.getResult());
                continue;
            }
            //实际入库数量
            if (OtherTargetsEnum.ACTUAL_STORAGE_QTY == baseOtherTargetEnum) {
                value.put(OtherTargetsEnum.ACTUAL_STORAGE_QTY.getName(), item.getResult());
            }
        }
    }

    /**
     * 处理采购中心批量指标(订单)
     *
     * @param result
     * @param esReturnDTOs
     * @return void
     **/
    private static void handlePurchaseTarget(Map<String, List<BigDecimal>> result, List<EsReturnDTO> esReturnDTOs, String name) {
        //仓库+sku
        String key;
        List<BigDecimal> list;
        for (EsReturnDTO item : esReturnDTOs) {
            key = item.getDeliverId() + item.getSkuCode();
            if (result != null) {
                list = result.get(key);
                if (list == null) {
                    item.getTargetMap().put(name, ZERO_BIGDECIMAL);
                } else {
                    item.getTargetMap().put(name, list);
                }
            } else {
                item.getTargetMap().put(name, ZERO_BIGDECIMAL);
            }
        }
    }

    /**
     * 实时库存
     *
     * @param result
     * @param esReturnDTOs
     * @return void
     **/
    private static void handleRealTimeStock(Map<String, List<BigDecimal>> result, List<EsReturnDTO> esReturnDTOs, String name) {
        //仓库+sku
        String key;
        List<BigDecimal> list;
        for (EsReturnDTO item : esReturnDTOs) {
            key = item.getDeliverId() + item.getSkuCode();
            if (result != null) {
                list = result.get(key);
                if (list == null) {
                    item.getTargetMap().put(name, ZERO_BIGDECIMAL);
                } else {
                    item.getTargetMap().put(name, list);
                }
            } else {
                item.getTargetMap().put(name, ZERO_BIGDECIMAL);
            }
        }
    }

    /**
     * 实际销量
     *
     * @param result
     * @param esReturnDTOs
     * @return void
     **/
    private static void handleActualSales(Map<String, List<BigDecimal>> result, List<EsReturnDTO> esReturnDTOs, Integer type) {
        //渠道+区域+sku
        String key;
        List<BigDecimal> list;
        for (EsReturnDTO item : esReturnDTOs) {
            //柱状图
            if (CommonConstants.ONE.equals(type)) {
                if (result != null) {
                    list = result.get("-");
                    if (list == null) {
                        item.getTargetMap().put(OtherTargetsEnum.ACTUAL_SALES.getName(), ZERO_BIGDECIMAL);
                    } else {
                        item.getTargetMap().put(OtherTargetsEnum.ACTUAL_SALES.getName(), list);
                    }
                } else {
                    item.getTargetMap().put(OtherTargetsEnum.ACTUAL_SALES.getName(), ZERO_BIGDECIMAL);
                }
            } else {
                //渠道转换
                String channel = ChannelUtil.getBigdataChannel(item.getChannel());
                key = channel + item.getAreaCode() + item.getSkuCode();
                if (result != null) {
                    list = result.get(key);
                    if (list == null) {
                        item.getTargetMap().put(OtherTargetsEnum.ACTUAL_SALES.getName(), ZERO_BIGDECIMAL);
                    } else {
                        item.getTargetMap().put(OtherTargetsEnum.ACTUAL_SALES.getName(), list);
                    }
                } else {
                    item.getTargetMap().put(OtherTargetsEnum.ACTUAL_SALES.getName(), ZERO_BIGDECIMAL);
                }
            }

        }
    }
}
